/// <reference path="../Rendering/forwardPipeline.ts" />
/// <reference path="../Core/lightCollector.ts" />

namespace FIREFLYX {
    /** 场景管理器 */
    export class SceneManager {
        private static readonly _cameras: Camera[] = [];
        private static readonly _rendererMap: Map<number, Renderer> = new Map();
        private static readonly _compStartSuccMap = new Map<number, boolean>();
        private static readonly _compStartFunMap = new Map<number, Component>();
        private static readonly _compUpdateFunMap = new Map<number, Component>();
        private static readonly _compLateUpdateFunMap = new Map<number, Component>();
        private static readonly _compOnRenderImageFunMap = new Map<number, Component>();
        private static readonly _compFunListMap = new Map<string, Map<number, Component>>();
        private static _renderContext: RenderContext;
        private static _renderPipeline: RenderPipeline;
        private static _lightCollector: LightCollector;
        private static _onRenderImageFun: (image: RenderTexture2D) => void;

        /** 渲染管线对象 */
        public static get renderPipeline() { return this._renderPipeline; }
        public static set renderPipeline(val) { this._renderPipeline = val; }
        /** 渲染上下文 */
        public static get renderContext() { return this._renderContext; }
        /** 灯光收集器 */
        public static get lightCollector() { return this._lightCollector; }

        public static init(gl: WebGL2RenderingContext) {
            GameObject.init(
                this.onGameObjectMake.bind(this),
                this.onGameObjectDispose.bind(this),
                this.onGameObjectActiveInHChange.bind(this),
                this.onComponentAdd.bind(this),
                this.onComponentRemove.bind(this),
            );
            this._renderPipeline = new ForwardPipeline();
            this._renderContext = new RenderContext(gl);
            this._lightCollector = new LightCollector();

            //设置 onRenderImage 函数
            this._onRenderImageFun = SceneManager.nodesOnRenderImage.bind(SceneManager);

            //组件 函数接口 容器设置
            this._compFunListMap.set(I_START_FUN, this._compStartFunMap);
            this._compFunListMap.set(I_UPDATE_FUN, this._compUpdateFunMap);
            this._compFunListMap.set(I_LATE_UPDATE_FUN, this._compLateUpdateFunMap);
            this._compFunListMap.set(I_ON_RENDER_IMAGE_FUN, this._compOnRenderImageFunMap);

            //事件注册
            GlobalEventManager.Instance.addListener("viweFrameChange", this.onViweFrameChange, this);
        }

        public static update(dt: number) {
            //初始状态
            this.start();
            this.ckEnable();

            //第一次 update
            this.nodesUpdate(dt);
            //第二次 update
            this.nodesLateUpdate(dt);
            //渲染
            this.renderer();
        }

        /** 当输出画面框有改变 */
        private static onViweFrameChange(e: string) {
            for (let i = 0, len = this._cameras.length; i < len; i++) {
                const cam = this._cameras[i];
                cam.reflashASP();
            }
        }

        /** 当实体被创建 */
        private static onGameObjectMake(e: GameObject) {
            //
        }

        /** 当实体被销毁 */
        private static onGameObjectDispose(e: GameObject) {
            //
        }

        /**
         * 组件与场景链接
         * @param c 组件
         * @param isLink    是否链接 , false 为断开
         */
        private static componentLink(c: Component, isLink: boolean) {
            //收集组件
            const cInstID = c.getInstanceID();
            const cFunsMap = this._compFunListMap;
            cFunsMap.forEach((v, k) => {
                if ((c as any)[k] != null) {
                    if (isLink) {
                        if (k == I_START_FUN && this._compStartSuccMap.get(cInstID)) return;    //一次执行 标记过了的 跳过
                        v.set(cInstID, c);
                    } else {
                        v.delete(cInstID);
                    }
                }
            });
        }

        /** 当实在层级体被激活状态改变 */
        private static onGameObjectActiveInHChange(e: GameObject) {
            const activeInHierarchy = e.activeInHierarchy;
            if (e.light) {
                if (activeInHierarchy) {
                    this._lightCollector.enableLight(e.light);
                } else {
                    this._lightCollector.disableLight(e.light);
                }
            } else if (e.camera) {
                const camera = e.camera;
                const idx = this._cameras.indexOf(camera);
                if (activeInHierarchy) {
                    if (idx == -1) this._cameras.push(camera);
                } else {
                    if (idx != -1) this._cameras.splice(idx, 1);
                }
            } else if (e.renderer) {
                const renderer = e.renderer;
                if (renderer) {
                    const instID = renderer.getInstanceID();
                    if (this._rendererMap.has(instID)) {
                        this._rendererMap.delete(instID);
                    }
                }
            }

            //组件link
            const compCount = e.componentCount;
            for (let i = 0; i < compCount; i++) {
                const comp = e.getComponent(i);
                if (!comp) continue;
                this.componentLink(comp, activeInHierarchy);
            }
        }

        /** 当组件被添加 */
        private static onComponentAdd(c: Component) {
            if (!c.entity) return;
            const cProt = Object.getPrototypeOf(c);
            if (!cProt) return;
            const cType: typeof Component = cProt.constructor;
            const cInstID = c.getInstanceID();
            switch (cType.useSign) {
                case "light":
                    const light = (c as Light);
                    this._lightCollector.enableLight(light);
                    break;
                case "camera":
                    const camera = (c as Camera);
                    if (this._cameras.indexOf(camera) == -1) {
                        this._cameras.push(camera);
                    }
                    break;
                case "renderer":
                    const instID = cInstID;
                    this._rendererMap.set(instID, (c as Renderer));
                    break;
                default:
            }

            //组件link
            if (!c.entity.activeInHierarchy) return;    //active 状态为 false 不收集 
            this.componentLink(c, true);
        }

        /** 当组件被移除 */
        private static onComponentRemove(c: Component) {
            const cProt = Object.getPrototypeOf(c);
            if (!cProt) return;
            const cType: typeof Component = cProt.constructor;
            switch (cType.useSign) {
                case "light":
                    const light = (c as Light);
                    this._lightCollector.disableLight(light);
                    break;
                case "camera":
                    const camera = (c as Camera);
                    const idx = this._cameras.indexOf(camera);
                    if (idx != -1) this._cameras.splice(idx, 1);
                    break;
                case "renderer":
                    const renderer = (c as Renderer);
                    const instID = renderer.getInstanceID();
                    if (this._rendererMap.has(instID)) { this._rendererMap.delete(instID); }
                    break;
                default:
            }

            //组件link
            this.componentLink(c, false);
        }

        /** 场景的节点初开始触发 */
        private static start() {
            if (this._compStartFunMap.size < 1) return;
            //遍历需要更新的节点列表
            this._compStartFunMap.forEach((v) => {
                (v as any)[I_START_FUN]();
                this._compStartSuccMap.set(v.getInstanceID(), true);
            });
            //start 执行完清理
            this._compStartFunMap.clear();
        }

        /** 场景的节点激活触发 */
        private static ckEnable() {
            //
        }

        /** 场景节点的更新 */
        private static nodesUpdate(dt: number) {
            //遍历需要更新的节点列表
            this._compUpdateFunMap.forEach((v) => {
                (v as any)[I_UPDATE_FUN](dt);
            });

            //event dispatch
            if (GlobalEventManager.Instance.listenerCount("sceneUpdate") > 0) {
                GlobalEventManager.Instance.dispatchEvent("sceneUpdate", dt);
            }
        }

        /** 场景节点的帧末更新 */
        private static nodesLateUpdate(dt: number) {
            //遍历需要更新的节点列表
            this._compLateUpdateFunMap.forEach((v) => {
                (v as any)[I_LATE_UPDATE_FUN](dt);
            });

            //event dispatch
            if (GlobalEventManager.Instance.listenerCount("sceneLateUpdate") > 0) {
                GlobalEventManager.Instance.dispatchEvent("sceneLateUpdate", dt);
            }
        }

        /** 场景后渲染到纹理 */
        private static nodesOnRenderImage(image: RenderTexture2D) {
            //遍历需要渲染的节点列表
            this._compOnRenderImageFunMap.forEach((v) => {
                let src: RenderTexture2D = null as any;
                let dest: RenderTexture2D = null as any;
                (v as any)[I_ON_RENDER_IMAGE_FUN](src, dest);
            });
        }

        /** 场景的渲染 */
        private static renderer() {
            let cams: Camera[] = this._cameras;
            if (cams.length < 1) { return; }
            let rPl = this._renderPipeline;
            if (!rPl) {
                console.warn(`render fial, renderPipeline is null.`);
                return;
            }
            //renderContext 准备数据
            let rCtx = this.renderContext;
            rCtx.rendererMap = this._rendererMap;
            rCtx.lightCollector = this._lightCollector;
            if (this._compOnRenderImageFunMap.size > 0) {
                rCtx.onRenderImageFun = this._onRenderImageFun;
            }
            //开始 render
            rPl.render(rCtx, cams);

            //render 结束
            rCtx.onRenderImageFun = null;
            //RenderTexture2D 临时对象清理，避免用户没有回收
            RenderTexture2D.ReleaseTemporaryAll();
        }

    }
}